33

昨天看到一个面试题:怎样实现 isNaN() 方法?

细细研究了一下 NaN,发现这个东西不常用,坑却异常多,颇有 “茴” 字有几种写法的感觉,这里记录下总结的东西吧。

NaN 是什么

NaNNot a Number(非数值),但它是一个特殊的数值,所以:

typeof(NaN)  // "number"

编码时很少直接使用 NaN,通常是在计算失败时,作为 Math 的某个方法的返回值出现的。

它有两个重要的性质:

  • NaN与任何值都不相等,包括NaN自身:
alert(NaN == NaN)  // false
alert(NaN === NaN)  // false
  • 任何涉及 NaN的操作都会返回NaN

哪些情况会产生NaN?

1. 计算

JS 在进行加减乘除运算之前,会先调用 Number()方法,将非数值的运算项转化为数值,如果转换失败就返回NaN,比如:

1-'a';   // NaN

首先是执行Number('a'),不能成功转化为数值,返回NaN,再利用NaN的第二条性质:任何涉及 NaN的操作都会返回NaN,所以最终的结果是NaN

2. 类型转换

当一个值不能被NumberparseIntparseFloat成功转换为数值,就返回NaN,举例:

Number('123.456abc');   // NaN
parseInt('123.456abc');  // 123
parseFloat('123.456abc'); // 123.456

Number('abc');  // NaN
parseInt('abc');  // NaN
parseFloat('abc');  // NaN

Number([]);  // 0
parseInt([]);  // NaN
parseFloat([]);  // NaN

Number('');  // 0
parseInt('');  // NaN
parseFloat('');  // NaN

Number({});  // NaN
parseInt({});  // NaN
parseFloat({});  // NaN

这里要注意三者之间的差异,我的理解是 parseIntparseFloat会尽量将参数值转化为数值。

关于isNaN()

isNaNwindow对象的一个方法,比较诡异的是:isNaN(x)并不是判断参数x本身是不是NaN,而是判断Number(x)是不是NaN。也就是说先用Number()去转化参数,再去判断转化的结果。返回的结果是一个布尔值。

isNaN(NaN);  // true
isNaN(123);  // false
isNaN('abc');  //true
isNaN('123abc'); //true

isNaN({});  // true,因为Number({})=NaN
isNaN('');  // false, 因为Number('')=0
isNaN([]);  // false,因为Number([])=0

可以看到最后, 空字符串'' 和 空数组[]显然是非数值,而isNaN返回了false,原因就是Number转换在作怪,这点还是很诡异的...所以我选择慎用...

那么isNaN是怎么实现的呢,原理就是利用NaN的第一条性质:NaN与任何值都不相等,包括NaN自身。

var isNaNA = function(value) {
    var n = Number(value);
    return n !== n;
};

先用Number()转换参数,再判断转换后的结果是不是不等于自身。

MDN 上给的实现方式是这样的:

var isNaNB = function(value) {
    var n = parseInt(value);
    return n !== n;
};

我觉得是有问题的,因为:

isNaN('123abc');    // true
isNaNA('123abc');   // true
isNaNB('123abc');   // false

Number.isNaN()

ES6 中的Number.isNaN()是一个判断NaN的升级版,和isNaN()不同的是,Number.isNaN()不会强制转化参数,直接对参数本身做判断,这样只有参数显示等于NaN,才会返回true

Number.isNaN(NaN);  // true,其他情况都返回 false

它的实现原理是:

function isNaNC (value) {
    return typeof(value) === "number" && isNaN(value);
}

算了,还是不纠结了....

参考

MDN isNaN()
JavaScript中的 NaN 与 isNaN


Leon
1.4k 声望1k 粉丝

下一篇 »
闭包理解